#include <gtest/gtest.h>
#include "config.h"

#if defined RUN_TESTS_GAME_ENGINE && RUN_TESTS_GAME_ENGINE > 0
#include "Vector2D.h"
#include "Matrix2D.h"
#include "Clock.h"
using namespace Math;
using namespace Timing;
#define M_PI  3.14159265358979323846f

inline bool closeEnough(float left,float right,float threshhold=.0000001)
{
	return abs(left - right) < threshhold;
}
TEST(Matrix2D,Rotate)
{
	Matrix2D op = Matrix2D::rotate(0);
	EXPECT_FLOAT_EQ(1.0f,op.r0c0);
	EXPECT_FLOAT_EQ(0.0f,op.r0c1);
	EXPECT_FLOAT_EQ(0.0f,op.r1c0);
	EXPECT_FLOAT_EQ(1.0f,op.r1c1);

	op = Matrix2D::rotate(M_PI);
	EXPECT_FLOAT_EQ(-1.0f,op.r0c0);
	EXPECT_TRUE(closeEnough(0.0f,op.r0c1));
	EXPECT_TRUE(closeEnough(0.0f,op.r1c0));
	EXPECT_FLOAT_EQ(-1.0f,op.r1c1);

	op = Matrix2D::rotate(M_PI/2);
	EXPECT_TRUE(closeEnough(0.0f,op.r0c0));
	EXPECT_FLOAT_EQ(-1.0f,op.r0c1);
	EXPECT_FLOAT_EQ(1.0f,op.r1c0);
	EXPECT_TRUE(closeEnough(0.0f,op.r1c1));

	op = Matrix2D::rotate(M_PI/4);
	const float sqrt2over2 = sqrt(2.0f)/2.0f;
	EXPECT_FLOAT_EQ(sqrt2over2,op.r0c0);
	EXPECT_FLOAT_EQ(-sqrt2over2,op.r0c1);
	EXPECT_FLOAT_EQ(sqrt2over2,op.r1c0);
	EXPECT_FLOAT_EQ(sqrt2over2,op.r1c1);

	op = Matrix2D::rotate(-M_PI/4);
	EXPECT_FLOAT_EQ(sqrt2over2,op.r0c0);
	EXPECT_FLOAT_EQ(sqrt2over2,op.r0c1);
	EXPECT_FLOAT_EQ(-sqrt2over2,op.r1c0);
	EXPECT_FLOAT_EQ(sqrt2over2,op.r1c1);

	const float sqrt3over2 = sqrt(3.0f)/2.0f;
	op = Matrix2D::rotate(M_PI/3);
	EXPECT_FLOAT_EQ(0.5f,op.r0c0);
	EXPECT_FLOAT_EQ(-sqrt3over2,op.r0c1);
	EXPECT_FLOAT_EQ(sqrt3over2,op.r1c0);
	EXPECT_FLOAT_EQ(0.5f,op.r1c1);

	op = Matrix2D::rotate(-M_PI/3);
	EXPECT_FLOAT_EQ(0.5f,op.r0c0);
	EXPECT_FLOAT_EQ(sqrt3over2,op.r0c1);
	EXPECT_FLOAT_EQ(-sqrt3over2,op.r1c0);
	EXPECT_FLOAT_EQ(0.5f,op.r1c1);
}

TEST(Matrix2D,Multiply)
{
	Matrix2D mat(2.0,4.0,4.0,2.0);
	Vector2D vec(2.0,2.0);

	Vector2D vec_result = mat*vec;
	EXPECT_FLOAT_EQ(12.0f,vec_result.x);
	EXPECT_FLOAT_EQ(12.0f,vec_result.y);
}
TEST(Matrix2D,Constructor)
{
	Matrix2D identity;
	EXPECT_FLOAT_EQ(1.0f,identity.r0c0);
	EXPECT_FLOAT_EQ(0.0f,identity.r0c1);
	EXPECT_FLOAT_EQ(0.0f,identity.r1c0);
	EXPECT_FLOAT_EQ(1.0f,identity.r1c1);
}


TEST(Vector2D,PlusEqOperator)
{
	Vector2D first(1.0f, 2.0f);
	Vector2D second = first;
	first += second;
	EXPECT_FLOAT_EQ(2.0f,first.x);
	EXPECT_FLOAT_EQ(4.0f,first.y);

}

TEST(Vector2D,SubtractEqOperator)
{
	Vector2D first(2.0f, 4.0f);
	Vector2D second(1.0f, 2.0f);
	first -= second;
	EXPECT_FLOAT_EQ(1.0f,first.x);
	EXPECT_FLOAT_EQ(2.0f,first.y);

}


TEST(Vector2D,Addition)
{
	Vector2D first(2.3f, 3.4f);
	Vector2D second(2.3f, 3.4f);
	Vector2D result = first + second;
	EXPECT_FLOAT_EQ(4.6f,result.x);
	EXPECT_FLOAT_EQ(6.8f,result.y);
	//EXPECT_EQ(60,variable);
}

TEST(Vector2D,ScalerMultiplication)
{
	Vector2D first(2.3f, 3.4f);
	float scaler = 3.0f;
	Vector2D  result1 = scaler*first;
	Vector2D  result2 = first*scaler;
	EXPECT_FLOAT_EQ(6.9f,result1.x);
	EXPECT_FLOAT_EQ(result1.x,result2.x);

	EXPECT_FLOAT_EQ(10.2f,result1.y);
	EXPECT_FLOAT_EQ(result1.y,result2.y);
}


TEST(Clock,Initialize)
{
	Clock clock;
	EXPECT_TRUE(clock.initialize());
	EXPECT_TRUE(clock.shutdown());
	
}

TEST(Clock,FrameTimeMeasuring)
{
	Clock clock;
	EXPECT_TRUE(clock.initialize());

	const int NUM_TESTS = 1 + rand() % 5; // Between 1 and 5
	const float THRESHOLD = 0.01f;

	for(int i=0;i<NUM_TESTS;i++)
	{
		int thisTestTimeMilliseconds = rand() % 5000;
		float thisTestTimeSeconds = thisTestTimeMilliseconds/1000.0f;

		clock.newFrame();
		printf(".");
		Sleep(thisTestTimeMilliseconds);
		clock.newFrame();

		float elapsedSeconds = clock.timeElapsedLastFrame();
		//if(elapsedSeconds < thisTestTimeSeconds)
		EXPECT_TRUE( (thisTestTimeSeconds-THRESHOLD) < elapsedSeconds);
		EXPECT_TRUE( elapsedSeconds < (thisTestTimeSeconds+THRESHOLD));

	}
	printf("\n");
	EXPECT_TRUE(clock.shutdown());
}
#endif
